#pragma once

namespace pb { namespace cfg {

    class Util
    {
    public:
        static bool loadLength(std::fstream&, unsigned int&);
        static bool loadName(std::fstream&, const unsigned int length, std::string&);
    };

}}

namespace pb { namespace cfg {

    template <class T>
    class Buffer
    {
    public:
        Buffer(unsigned int);
        Buffer(unsigned int, const T);
        Buffer(const Buffer<T>&);
        ~Buffer();        

    public:
        unsigned int size() const;
        T* data();
        T& operator[](unsigned int);
        T  operator[](unsigned int) const;
        bool operator == (const Buffer<T>&);
        bool operator != (const Buffer<T>&);
        Buffer<T>& operator=(const Buffer<T>&);

    private:
        unsigned int    m_size;
        T*              m_data;
    };

    template <class T>
    Buffer<T>::Buffer(unsigned int size)
        : m_size(size)
        , m_data(0)
    {
        if (m_size > 0)
            m_data = new T [m_size];
    }

    template <class T>
    Buffer<T>::Buffer(unsigned int size, const T value)
        : m_size(size)
        , m_data(0)
    {
        if (m_size > 0)
        {
            m_data = new T [m_size];
            for (unsigned int i = 0; i < m_size; ++i)
                m_data[i] = value;
        }
    }

    template <class T>
    Buffer<T>::Buffer(const Buffer<T>& that)
        : m_size(that.size())
        , m_data(0)
    {
        if (m_size > 0)
        {
            m_data = new T[m_size];

            for (unsigned int i = 0; i < m_size; ++i)
                m_data[i] = that[i];
        }
    }

    template <class T>
    Buffer<T>::~Buffer()
    {
        if (m_data)
            delete [] m_data;
    }

    template <class T>
    unsigned int Buffer<T>::size() const
    {
        return m_size;
    }

    template <class T>
    T* Buffer<T>::data()
    {
        return m_data;
    }

    template <class T>
    T& Buffer<T>::operator [] (unsigned int index)
    {
        assert(index < m_size);
        return m_data[index];
    }

    template <class T>
    T Buffer<T>::operator [] (unsigned int index) const
    {
        assert(index < m_size);
        return m_data[index];
    }

    template <class T>
    bool Buffer<T>::operator == (const Buffer<T>& that)
    {
        if (m_size != that.size())
            return false;

        if (m_size > 0)
            for (unsigned int i = 0; i < m_size; ++i)
                if (m_data[i] != that[i])
                    return false;

        return true;
    }

    template <class T>
    bool Buffer<T>::operator != (const Buffer<T>& that)
    {
        return !(this->operator ==(that));
    }

    template<class T>
    Buffer<T>& Buffer<T>::operator=(const Buffer<T>& that)
    {
        if (m_data)
        {
            delete m_data;
            m_data = 0;
        }

        m_size = that.size();

        if (m_size > 0)
        {
            m_data = new T[m_size];

            for (unsigned int i = 0; i < m_size; ++i)
                m_data[i] = that[i];
        }

        return *this;
    }

}}